{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Food Manufacture I\n",
    "\n",
    "## Objective and Prerequisites \n",
    "\n",
    "If you’re hungry for a mathematical optimization challenge, then try this food manufacturing problem. You’ll learn how to create an optimal multi-period production plan for a product that requires a number of ingredients – each of which has different costs, restrictions, and features.\n",
    "\n",
    "More information on this type of model can be found in example #1 of the fifth edition of Modeling Building in Mathematical Programming by H. P. Williams on pages 253 – 254 and 296 – 298.\n",
    "\n",
    "This modeling example is at the intermediate level, where we assume that you know Python and are familiar with the Gurobi Python API. In addition, you should have some knowledge about building mathematical optimization models.\n",
    "\n",
    "**Download the Repository** <br />\n",
    "You can download the repository containing this and other examples by clicking [here](https://github.com/Gurobi/modeling-examples/archive/master.zip). \n",
    "\n",
    "---\n",
    "## Problem Description\n",
    "\n",
    "A manufacturer needs to refine several raw oils and blend them together to produce a given food product that can be sold. The raw oils required can be divided into two categories:\n",
    "\n",
    "\n",
    "| Category        | Oil         |\n",
    "| ------------- |-------------| \n",
    "| Vegetable oils:|  VEG 1<br>VEG 2 | \n",
    "| Non-vegetable oils:     | OIL 1<br>OIL 2<br>OIL 3      |\n",
    "\n",
    "The manufacturer can choose to buy raw oils for the current month and/or buy them on the futures market for delivery in a subsequent month. Prices for immediate delivery and in the futures market are given below in USD/ton:\n",
    "\n",
    "| Month |\tVEG 1 |\tVEG 2 |\tOIL 1 |\tOIL 2 |\tOIL 3|\n",
    "| ------------- |-------------| -------------| -------------| -------------| -------------| \n",
    "| January| 110 |\t120 |\t130 |\t110 |\t115|\n",
    "| February |130 |\t130 |\t110 |\t90|\t115|\n",
    "| March |110 |\t140 |\t130 |\t100 |\t95|\n",
    "| April |120 |\t110 |\t120 |\t120 |\t125|\n",
    "| May | 100 |\t120 |\t150 |\t110 |\t105|\n",
    "| June |  \t90 |\t100 |\t140 |\t80| \t135 |\n",
    "\n",
    "There are a number of additional factors that must be taken into account. These include:\n",
    "\n",
    "1. The final food product sells for $\\$150$ per ton.\n",
    "2. Each category of oil (vegetable and non-vegetable) needs to be refined on a different production line.\n",
    "3. There is limited refinement capacity such that in any given month a maximum of 200 tons of vegetable oils and 250 tons of non-vegetable oils can be refined.\n",
    "4. Also, there is no waste in the refinement process, so the sum of the raw oils refined will equal the amount of refined oils available.\n",
    "5. The cost of refining the oils may be ignored.\n",
    "\n",
    "In addition to the refining limits above, there are limits to the amount of raw oils that can be stored for future use, and there is a cost associated with each ton of oil stored. The limit is 1,000 tons of each raw oil and the storage cost is $\\$5$ per ton per month. The manufacturer cannot store the produced food product or the refined oils.\n",
    "\n",
    "The final food product must have a hardness between three and six on a given hardness scale. For the purposes of the model, hardness blends linearly and the hardness of each raw oil is:\n",
    "\n",
    "|Oils |\tHardness|\n",
    "| ------------- |-------------| \n",
    "|VEG 1 |\t8.8|\n",
    "|VEG 2 |\t6.1|\n",
    "|OIL 1 |\t2.0|\n",
    "|OIL2 |\t4.2|\n",
    "|OIL 3| \t5.0|\n",
    "\n",
    "At the start of January, there are 500 tons of each type of raw oil in storage. For the purpose of the model, this should also be the level of raw oils in storage at the end of June.\n",
    "\n",
    "Given the above information, what monthly buying and manufacturing decisions should be made in order to maximize profit?\n",
    "\n",
    "---\n",
    "## Model Formulation\n",
    "\n",
    "### Sets and Indices\n",
    "\n",
    "$t \\in \\text{Months}=\\{\\text{Jan},\\text{Feb},\\text{Mar},\\text{Apr},\\text{May},\\text{Jun}\\}$: Set of months.\n",
    "\n",
    "$V=\\{\\text{VEG1},\\text{VEG2}\\}$: Set of vegetable oils.\n",
    "\n",
    "$N=\\{\\text{OIL1},\\text{OIL2},\\text{OIL3}\\}$: Set of non-vegetable oils.\n",
    "\n",
    "$o \\in \\text{Oils} = V \\cup N$: Set of oils.\n",
    "\n",
    "### Parameters\n",
    "\n",
    "$\\text{price} \\in \\mathbb{R}^+$: Sale price of the final product.\n",
    "\n",
    "$\\text{init_store} \\in \\mathbb{R}^+$: Initial storage amount in tons.\n",
    "\n",
    "$\\text{target_store} \\in \\mathbb{R}^+$: Target storage amount in tons.\n",
    "\n",
    "$\\text{holding_cost} \\in \\mathbb{R}^+$: Monthly cost (in USD/ton/month) of keeping in inventory a ton of oil.\n",
    "\n",
    "$\\text{veg_cap} \\in \\mathbb{R}^+$: Installed capacity (in tons) to refine vegetable oils.\n",
    "\n",
    "$\\text{oil_cap} \\in \\mathbb{R}^+$: Installed capacity (in tons) to refine non-vegetable oils.\n",
    "\n",
    "$\\text{min_hardness} \\in \\mathbb{R}^+$: lowest hardness allowed for the final product.\n",
    "\n",
    "$\\text{max_hardness} \\in \\mathbb{R}^+$: highest hardness allowed for the final product.\n",
    "\n",
    "$\\text{hardness}_o \\in \\mathbb{R}^+$: Hardness of oil $o$.\n",
    "\n",
    "$\\text{cost}_{t,o} \\in \\mathbb{R}^+$: Estimated purchase price for oil $o$ at month $t$.\n",
    "\n",
    "\n",
    "### Decision Variables\n",
    "\n",
    "$\\text{produce}_t \\in \\mathbb{R}^+$: Tons of food to produce at month $t$.\n",
    "\n",
    "$\\text{buy}_{t,o} \\in \\mathbb{R}^+$: Tons of oil $o$ to buy at month $t$.\n",
    "\n",
    "$\\text{consume}_{t,o} \\in \\mathbb{R}^+$: Tons of oil $o$ to use at month $t$.\n",
    "\n",
    "$\\text{store}_{t,o} \\in \\mathbb{R}^+$: Tons of oil $o$ to store at month $t$.\n",
    "\n",
    "\n",
    "### Objective Function\n",
    "\n",
    "- **Profit**: Maximize the total profit (in USD) of the planning horizon.\n",
    "\n",
    "\\begin{equation}\n",
    "\\text{Maximize} \\quad Z = \\sum_{t \\in \\text{Months}}\\text{price}*\\text{produce}_t - \\sum_{t \\in \\text{Months}}\\sum_{o \\in \\text{Oils}}(\\text{cost}_{t,o}*\\text{consume}_{t,o} + \\text{holding_cost}*\\text{store}_{t,o})\n",
    "\\tag{0}\n",
    "\\end{equation}\n",
    "\n",
    "### Constraints\n",
    "\n",
    "- **Initial Balance:** The Tons of oil $o$ purchased in January and the ones previously stored should be equal to the Tons of said oil consumed and stored in that month.\n",
    "\n",
    "\\begin{equation}\n",
    "\\text{init_store} + \\text{buy}_{Jan,o} = \\text{consume}_{Jan,o} + \\text{store}_{Jan,o} \\quad \\forall o \\in \\text{Oils}\n",
    "\\tag{1}\n",
    "\\end{equation}\n",
    "\n",
    "- **Balance:** The Tons of oil $o$ purchased in month $t$ and the ones previously stored should be equal to the Tons of said oil consumed and stored in that month.\n",
    "\n",
    "\\begin{equation}\n",
    "\\text{store}_{t-1,o} + \\text{buy}_{t,o} = \\text{consume}_{t,o} + \\text{store}_{t,o} \\quad \\forall (t,o) \\in \\text{Months} \\setminus \\{\\text{Jan}\\} \\times \\text{Oils}\n",
    "\\tag{2}\n",
    "\\end{equation}\n",
    "\n",
    "- **Inventory Target**: The Tons of oil $o$ kept in inventory at the end of the planning horizon should hit the target.\n",
    "\n",
    "\\begin{equation}\n",
    "\\text{store}_{Jun,o} = \\text{target_store} \\quad \\forall o \\in \\text{Oils}\n",
    "\\tag{3}\n",
    "\\end{equation}\n",
    "\n",
    "- **Refinement Capacity**: Total Tons of oil $o$ consumed in month $t$ cannot exceed the refinement capacity.\n",
    "\n",
    "\\begin{equation}\n",
    "\\sum_{o \\in V}\\text{consume}_{t,o} \\leq \\text{veg_cap} \\quad \\forall t \\in \\text{Months}\n",
    "\\tag{4.1}\n",
    "\\end{equation}\n",
    "\n",
    "\\begin{equation}\n",
    "\\sum_{o \\in N}\\text{consume}_{t,o} \\leq \\text{oil_cap} \\quad \\forall t \\in \\text{Months}\n",
    "\\tag{4.2}\n",
    "\\end{equation}\n",
    "\n",
    "- **Hardness**: The hardness value of the food produced in month $t$ should be within tolerances.\n",
    "\n",
    "\\begin{equation}\n",
    "\\text{min_hardness}*\\text{produce}_t \\leq \\sum_{o \\in \\text{Oils}} \\text{hardness}_o*\\text{consume}_{t,o} \\leq \\text{max_hardness}*\\text{produce}_t \\quad \\forall t \\in \\text{Months}\n",
    "\\tag{5}\n",
    "\\end{equation}\n",
    "\n",
    "- **Mass Conservation**: Total Tons of oil consumed in month $t$ should be equal to the Tons of the food produced in that month.\n",
    "\n",
    "\\begin{equation}\n",
    "\\sum_{o \\in \\text{Oils}}\\text{consume}_{t,o} = \\text{produce}_t \\quad \\forall t \\in \\text{Months}\n",
    "\\tag{6}\n",
    "\\end{equation}\n",
    "\n",
    "---\n",
    "## Python Implementation\n",
    "\n",
    "We import the Gurobi Python Module and other Python libraries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install gurobipy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "import gurobipy as gp\n",
    "from gurobipy import GRB\n",
    "\n",
    "# tested with Python 3.7 & Gurobi 9"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Input Data\n",
    "We define all the input data of the model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Parameters\n",
    "\n",
    "months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"]\n",
    "\n",
    "oils = [\"VEG1\", \"VEG2\", \"OIL1\", \"OIL2\", \"OIL3\"]\n",
    "\n",
    "cost = {\n",
    "    ('Jan', 'VEG1'): 110,\n",
    "    ('Jan', 'VEG2'): 120,\n",
    "    ('Jan', 'OIL1'): 130,\n",
    "    ('Jan', 'OIL2'): 110,\n",
    "    ('Jan', 'OIL3'): 115,\n",
    "    ('Feb', 'VEG1'): 130,\n",
    "    ('Feb', 'VEG2'): 130,\n",
    "    ('Feb', 'OIL1'): 110,\n",
    "    ('Feb', 'OIL2'): 90,\n",
    "    ('Feb', 'OIL3'): 115,\n",
    "    ('Mar', 'VEG1'): 110,\n",
    "    ('Mar', 'VEG2'): 140,\n",
    "    ('Mar', 'OIL1'): 130,\n",
    "    ('Mar', 'OIL2'): 100,\n",
    "    ('Mar', 'OIL3'): 95,\n",
    "    ('Apr', 'VEG1'): 120,\n",
    "    ('Apr', 'VEG2'): 110,\n",
    "    ('Apr', 'OIL1'): 120,\n",
    "    ('Apr', 'OIL2'): 120,\n",
    "    ('Apr', 'OIL3'): 125,\n",
    "    ('May', 'VEG1'): 100,\n",
    "    ('May', 'VEG2'): 120,\n",
    "    ('May', 'OIL1'): 150,\n",
    "    ('May', 'OIL2'): 110,\n",
    "    ('May', 'OIL3'): 105,\n",
    "    ('Jun', 'VEG1'): 90,\n",
    "    ('Jun', 'VEG2'): 100,\n",
    "    ('Jun', 'OIL1'): 140,\n",
    "    ('Jun', 'OIL2'): 80,\n",
    "    ('Jun', 'OIL3'): 135\n",
    "}\n",
    "\n",
    "\n",
    "hardness = {\"VEG1\": 8.8, \"VEG2\": 6.1, \"OIL1\": 2.0, \"OIL2\": 4.2, \"OIL3\": 5.0}\n",
    "\n",
    "price = 150\n",
    "init_store = 500\n",
    "target_store = 500\n",
    "veg_cap = 200\n",
    "oil_cap = 250\n",
    "\n",
    "min_hardness = 3\n",
    "max_hardness = 6\n",
    "holding_cost = 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Model Deployment\n",
    "We create a model and the variables. For each period, we create a variable which will take into account the value of the food produced. For each product (5 kinds of oils) and each period, we will create variables for the amount that gets bought, used and, stored."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using license file c:\\gurobi\\gurobi.lic\n"
     ]
    }
   ],
   "source": [
    "food = gp.Model('Food Manufacture I')\n",
    "# Quantity of food produced in each period\n",
    "produce = food.addVars(months, name=\"Produce\")\n",
    "# Quantity bought of each product in each period\n",
    "buy = food.addVars(months, oils, name = \"Buy\")\n",
    "# Quantity used of each product  in each period\n",
    "consume = food.addVars(months, oils, name = \"Use\")\n",
    "# Quantity stored of each product  in each period\n",
    "store = food.addVars(months, oils, name = \"Store\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we insert the constraints. The balance constraints ensure that the amount of oil that is in the storage in the previous period plus the amount that gets purchased equals the amount that is used plus the amount that is stored in the current period (for each oil). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "#1. Initial Balance\n",
    "Balance0 = food.addConstrs((init_store + buy[months[0], oil]\n",
    "                 == consume[months[0], oil] + store[months[0], oil]\n",
    "                 for oil in oils), \"Initial_Balance\")\n",
    "\n",
    "#2. Balance\n",
    "Balance = food.addConstrs((store[months[months.index(month)-1], oil] + buy[month, oil]\n",
    "                 == consume[month, oil] + store[month, oil]\n",
    "                 for oil in oils for month in months if month != month[0]), \"Balance\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Inventory Target constraints force that at the end of the last period the storage contains the initial amount of each product."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#3. Inventory Target\n",
    "TargetInv = food.addConstrs((store[months[-1], oil] == target_store for oil in oils),\"End_Balance\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The capacity constraints restrict the amount of veg and non-veg oils that can be processed per period."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#4.1 Vegetable Oil Capacity\n",
    "VegCapacity = food.addConstrs((gp.quicksum(consume[month, oil] for oil in oils if \"VEG\" in oil)\n",
    "                 <= veg_cap for month in months), \"Capacity_Veg\")\n",
    "\n",
    "#4.2 Non-vegetable Oil Capacity\n",
    "NonVegCapacity = food.addConstrs((gp.quicksum(consume[month, oil] for oil in oils if \"OIL\" in oil)\n",
    "                 <= oil_cap for month in months), \"Capacity_Oil\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The hardness constraints limit the hardness of the final product, which needs to remain between 3 and 6."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "#5. Hardness\n",
    "HardnessMin = food.addConstrs((gp.quicksum(hardness[oil]*consume[month, oil] for oil in oils)\n",
    "                 >= min_hardness*produce[month] for month in months), \"Hardness_lower\")\n",
    "HardnessMax = food.addConstrs((gp.quicksum(hardness[oil]*consume[month, oil] for oil in oils)\n",
    "                 <= max_hardness*produce[month] for month in months), \"Hardness_upper\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Mass Conservation constraints ensure that the amount of oil used in each period equals the food produced in this period."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "#6. Mass Conservation\n",
    "MassConservation = food.addConstrs((consume.sum(month) == produce[month] for month in months), \"Mass_conservation\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The objective is to maximize the profit of the company, which includes the revenue as well as the costs for buying and storing the used products."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "#0. Objective Function\n",
    "obj = price*produce.sum() - buy.prod(cost) - holding_cost*store.sum()\n",
    "food.setObjective(obj, GRB.MAXIMIZE) # maximize profit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we start the optimization and Gurobi finds the optimal solution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gurobi Optimizer version 9.1.0 build v9.1.0rc0 (win64)\n",
      "Thread count: 4 physical cores, 8 logical processors, using up to 8 threads\n",
      "Optimize a model with 70 rows, 96 columns and 278 nonzeros\n",
      "Model fingerprint: 0xd588eb19\n",
      "Coefficient statistics:\n",
      "  Matrix range     [1e+00, 9e+00]\n",
      "  Objective range  [5e+00, 2e+02]\n",
      "  Bounds range     [0e+00, 0e+00]\n",
      "  RHS range        [2e+02, 5e+02]\n",
      "Presolve removed 33 rows and 45 columns\n",
      "Presolve time: 0.01s\n",
      "Presolved: 37 rows, 51 columns, 149 nonzeros\n",
      "\n",
      "Iteration    Objective       Primal Inf.    Dual Inf.      Time\n",
      "       0    3.7375000e+05   1.703125e+03   0.000000e+00      0s\n",
      "      29    1.0784259e+05   0.000000e+00   0.000000e+00      0s\n",
      "\n",
      "Solved in 29 iterations and 0.01 seconds\n",
      "Optimal objective  1.078425926e+05\n"
     ]
    }
   ],
   "source": [
    "food.optimize()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## Analysis\n",
    "\n",
    "The highest profit we can hope for is $\\$107,842.6$. Let's see an optimal solution needed to achieve that figure (there are alternative optimal solutions):\n",
    "\n",
    "### Purchase Plan\n",
    "\n",
    "This plan defines the amount of vegetable oil (VEG) and non-vegetable oil (OIL) that we need to purchase during the planning horizon. For example, 659.3 tons of vegetable oil of type VEG1 needs to be bought in June."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>VEG1</th>\n",
       "      <th>VEG2</th>\n",
       "      <th>OIL1</th>\n",
       "      <th>OIL2</th>\n",
       "      <th>OIL3</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Jan</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Feb</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>250.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Mar</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Apr</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>May</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>500.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Jun</th>\n",
       "      <td>659.3</td>\n",
       "      <td>540.7</td>\n",
       "      <td>0.0</td>\n",
       "      <td>750.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      VEG1   VEG2  OIL1   OIL2   OIL3\n",
       "Jan    0.0    0.0   0.0    0.0    0.0\n",
       "Feb    0.0    0.0   0.0  250.0    0.0\n",
       "Mar    0.0    0.0   0.0    0.0    0.0\n",
       "Apr    0.0    0.0   0.0    0.0    0.0\n",
       "May    0.0    0.0   0.0    0.0  500.0\n",
       "Jun  659.3  540.7   0.0  750.0    0.0"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rows = months.copy()\n",
    "columns = oils.copy()\n",
    "purchase_plan = pd.DataFrame(columns=columns, index=rows, data=0.0)\n",
    "\n",
    "for month, oil in buy.keys():\n",
    "    if (abs(buy[month, oil].x) > 1e-6):\n",
    "        purchase_plan.loc[month, oil] = np.round(buy[month, oil].x, 1)\n",
    "purchase_plan"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Monthly Consumption\n",
    "\n",
    "This plan determines the amount of vegetable oil (VEG) and non-vegetable oil (OIL) consumed during the planning horizon. For example, 200 tons of vegetable oil of type VEG2 is consumed in January."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>VEG1</th>\n",
       "      <th>VEG2</th>\n",
       "      <th>OIL1</th>\n",
       "      <th>OIL2</th>\n",
       "      <th>OIL3</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Jan</th>\n",
       "      <td>0.0</td>\n",
       "      <td>200.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>250.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Feb</th>\n",
       "      <td>85.2</td>\n",
       "      <td>114.8</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>250.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Mar</th>\n",
       "      <td>96.3</td>\n",
       "      <td>103.7</td>\n",
       "      <td>0.0</td>\n",
       "      <td>250.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Apr</th>\n",
       "      <td>159.3</td>\n",
       "      <td>40.7</td>\n",
       "      <td>0.0</td>\n",
       "      <td>250.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>May</th>\n",
       "      <td>159.3</td>\n",
       "      <td>40.7</td>\n",
       "      <td>0.0</td>\n",
       "      <td>250.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Jun</th>\n",
       "      <td>159.3</td>\n",
       "      <td>40.7</td>\n",
       "      <td>0.0</td>\n",
       "      <td>250.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      VEG1   VEG2  OIL1   OIL2   OIL3\n",
       "Jan    0.0  200.0   0.0    0.0  250.0\n",
       "Feb   85.2  114.8   0.0    0.0  250.0\n",
       "Mar   96.3  103.7   0.0  250.0    0.0\n",
       "Apr  159.3   40.7   0.0  250.0    0.0\n",
       "May  159.3   40.7   0.0  250.0    0.0\n",
       "Jun  159.3   40.7   0.0  250.0    0.0"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rows = months.copy()\n",
    "columns = oils.copy()\n",
    "reqs = pd.DataFrame(columns=columns, index=rows, data=0.0)\n",
    "\n",
    "for month, oil in consume.keys():\n",
    "    if (abs(consume[month, oil].x) > 1e-6):\n",
    "        reqs.loc[month, oil] = np.round(consume[month, oil].x, 1)\n",
    "reqs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Inventory Plan\n",
    "\n",
    "This plan reflects the amount of vegetable oil (VEG) and non-vegetable oil (OIL) in inventory at the end of each period of  the planning horizon. For example, at the end of February we have 500 tons of Non-vegetable oil of type OIL1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>VEG1</th>\n",
       "      <th>VEG2</th>\n",
       "      <th>OIL1</th>\n",
       "      <th>OIL2</th>\n",
       "      <th>OIL3</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Jan</th>\n",
       "      <td>500.0</td>\n",
       "      <td>300.0</td>\n",
       "      <td>500.0</td>\n",
       "      <td>500.0</td>\n",
       "      <td>250.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Feb</th>\n",
       "      <td>414.8</td>\n",
       "      <td>185.2</td>\n",
       "      <td>500.0</td>\n",
       "      <td>750.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Mar</th>\n",
       "      <td>318.5</td>\n",
       "      <td>81.5</td>\n",
       "      <td>500.0</td>\n",
       "      <td>500.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Apr</th>\n",
       "      <td>159.3</td>\n",
       "      <td>40.7</td>\n",
       "      <td>500.0</td>\n",
       "      <td>250.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>May</th>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>500.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>500.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Jun</th>\n",
       "      <td>500.0</td>\n",
       "      <td>500.0</td>\n",
       "      <td>500.0</td>\n",
       "      <td>500.0</td>\n",
       "      <td>500.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      VEG1   VEG2   OIL1   OIL2   OIL3\n",
       "Jan  500.0  300.0  500.0  500.0  250.0\n",
       "Feb  414.8  185.2  500.0  750.0    0.0\n",
       "Mar  318.5   81.5  500.0  500.0    0.0\n",
       "Apr  159.3   40.7  500.0  250.0    0.0\n",
       "May    0.0    0.0  500.0    0.0  500.0\n",
       "Jun  500.0  500.0  500.0  500.0  500.0"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rows = months.copy()\n",
    "columns = oils.copy()\n",
    "store_plan = pd.DataFrame(columns=columns, index=rows, data=0.0)\n",
    "\n",
    "for month, oil in store.keys():\n",
    "    if (abs(store[month, oil].x) > 1e-6):\n",
    "        store_plan.loc[month, oil] = np.round(store[month, oil].x, 1)\n",
    "store_plan"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note:** If you want to write your solution to a file, rather than print it to the terminal, you can use the model.write() command. An example implementation is:\n",
    "\n",
    "`food.write(\"food-manufacture-1-output.sol\")`\n",
    "\n",
    "---\n",
    "## References\n",
    "\n",
    "H. Paul Williams, Model Building in Mathematical Programming, fifth edition.\n",
    "\n",
    "Copyright © 2020 Gurobi Optimization, LLC"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
